# coding: utf-8
## coding: latin-1
## å-ä-ö -£

#TODO add feature so that correction string is uniform and can easily be 
#    returned to e.g. web form

import formencode
from formencode import validators
from values import reserved_words
import re

def validator_obj(type):
    '''
    Converts a string to a matching corresponding formencode validation object.
    '''
    exec('vob = validators.{0}'.format(type))
    return vob
      
def do(x, validator):
    '''
    Validates that x validates against validator where that is a string
    matching a formencode validator object name, see
    http://www.formencode.org//module-formencode.validators-index.html for the
    full index of validators.
    
    Examples: "MinLength(6)", "Email()", "PlainText(), "NotEmpty"
    
    Returns: Success (Bool), value
             False, error message
    
    '''
    validator = validator_obj(validator)        
    try:
        return (True, unicode(validator.to_python(x)))
    except formencode.Invalid, e:
        return (False, e.msg)

def can_unicode(content):
    '''Checks that content can be converted to unicode, and does conversion'''
    valid = True
    try:
        content = unicode(content)
    except UnicodeDecodeError, e:
        valid = False
        content = unicode("Must be  characters A-Z 0-9 or _")
    return valid, content

def not_empty(content):
    #FIXME AND
    # return str(value)
    valid = True
    if content in [None,  [], (), '',0, ' ']: 
    #and len(unicode(content)) < 1:
        valid = False
        content = "Entry cannot be empty"
    if len(str(content)) < 1:
        valid = False
        content = "Entry cannot be empty"
    return valid, unicode(content)  

def not_reserved(content):
    ''' Checks if word is in reserved word list and does not begin with
    underscore'''
    valid = True
    # if not type(content) == str:
    if not type(content) == unicode:
            valid = False    
    elif len(content)<1:
        valid =  False
    elif content[0] == '_': # underscore reserved so a source of future reserved words
        valid =  False
        content = 'Entry must not begin with "_"' 
    elif content.lower() in reserved_words(): # last as its time consuming
        valid =  False
        content = '"{0}" is a reserved word and cannot be used'.format(str(content))
    return valid , content
    valid = True    
#    if content.lower() in words():
#        content = 'Error:"{0}" is a reserved word and cannot be used'.format(content)
#        valid = False 
    return valid, content

def regex(content, expression):
    # print 5, content
    test_re = re.compile(expression)
    valid = bool(test_re.match(content))
    # r = re.compile(expression)
    # valid = r.match(content)
    return valid, content
    
def not_number(content):
    ''' Checks that word could not be confused as a number. Important when
    retrieving an object from db by name or by id'''
    valid = True
    content = str(content)
    valid, content = regex(content,'^-*[0-9]*\.*[0-9]+$')
    valid = not valid
    return valid, unicode(content)
    

def name(content, min_length=3, max_length = 64):
    ''' Standard validation for name fields'''
    valid = True
    while valid:
        valid, content = not_empty(content)
        if not valid: break
        valid,content = can_unicode(content)
        if not valid: break
        valid, content = do(content, 'PlainText') 
        if not valid: break         
        valid, content = do(content, "MinLength({0})".format(min_length))
        if not valid: break
        valid, content = do(content, "MaxLength({0})".format(max_length))
        if not valid: break
        valid, content = not_reserved(content)
        if not valid: break
        valid, content = not_number(content)
        break
    return valid, content

class Name(object):
    EN = '''Names must be a least five characters long'''
    def __init__(self, value):
        self.value = value
    
    def check(self):
        valid = True
        content = self.value
        min_length = 3
        max_length = 64
        while valid:
            valid, content = not_empty(content)
            if not valid: break
            valid,content = can_unicode(content)
            if not valid: break
            valid, content = do(content, 'PlainText') 
            if not valid: break         
            valid, content = do(content, "MinLength({0})".format(min_length))
            if not valid: break
            valid, content = do(content, "MaxLength({0})".format(max_length))
            if not valid: break
            valid, content = not_reserved(content)
            break
        self.value = content
        self.valid = valid
        return valid, content
        

if __name__ == '__main__':
    pass
    # print 10, regex('123','^[0-9]+$')
    print not_number('-1.a23')

